#include "interop/ImageHandler.hpp"

#include "interop/ElfInterop.hpp"
#include "rewine/LoaderSingleton.hpp"
#include "rewine/impl/CPeImage.hpp"

using rewine::IImage;
using std::shared_ptr;
using std::string;

namespace rewine
{

rw_image_t
PImageToHandle(IImage *p) {
    return reinterpret_cast<rw_image_t>(p);
}

IImage *
HandleToPImage(rw_image_t handle) {
    return reinterpret_cast<IImage *>(handle);
}

} // namespace rewine

rw_image_t
rewine_OpenImage(const char *cname) {
    auto pImage = rewine::g_Loader->openImage(string(cname), true);
    if (!pImage) {
        return nullptr;
    }
    return rewine::PImageToHandle(pImage);
}

rw_image_t
rewine_OpenImageFd(int fd) {
    auto pImage = rewine::g_Loader->openImage(fd, true);
    if (!pImage) {
        return nullptr;
    }
    return rewine::PImageToHandle(pImage);
}

void
rewine_CloseImage(rw_image_t handle) {
    if (handle) {
        auto pImage = rewine::HandleToPImage(handle);
        rewine::g_Loader->closeImage(pImage);
    }
}

void *
rewine_GetImageBase(rw_image_t handle) {
    if (handle) {
        auto pImage = rewine::HandleToPImage(handle);
        if (pImage->flavour() == rewine::ImageFlavour::PE) {
            auto peImage = (rewine::CPeImage *) pImage;
            return peImage->getImageBase();
        }
    }
    return nullptr;
}

size_t
rewine_GetImageSize(rw_image_t handle) {
    if (handle) {
        auto pImage = rewine::HandleToPImage(handle);
        if (pImage->flavour() == rewine::ImageFlavour::PE) {
            auto peImage = (rewine::CPeImage *) pImage;
            return peImage->getImageSize();
        }
    }
    return 0;
}

void *
rewine_GetEntryPoint(rw_image_t handle) {
    if (handle) {
        auto pImage = rewine::HandleToPImage(handle);
        if (pImage->flavour() == rewine::ImageFlavour::PE) {
            auto peImage = (rewine::CPeImage *) pImage;
            return peImage->getEntryPoint();
        }
    }
    return nullptr;
}

rw_elf_t
rewine_GetELFInfo(rw_image_t handle, const char *caller) {
    if (handle) {
        auto pImage = rewine::HandleToPImage(handle);
        if (pImage->flavour() == rewine::ImageFlavour::PE) {
            auto peImage = (rewine::CPeImage *) pImage;
            rewine::ElfInterop em(peImage);
            return em.buildELFInfo(caller);
        }
    }
    return rw_elf_t();
}

void
rewine_UpdateELFSymtab(rw_image_t handle, uint32_t symcnt, void *symtab0, void *strtab0) {
    if (handle) {
        auto pImage = rewine::HandleToPImage(handle);
        if (pImage->flavour() == rewine::ImageFlavour::PE) {
            auto peImage = (rewine::CPeImage *) pImage;
            rewine::ElfInterop em(peImage);
            em.updateSymtab(symcnt, symtab0, strtab0);
        }
    }
}
